<?php

/**
 * 密码加密算法
 * @param type $password 明文密码
 * @return type
 */
function sf_hashcrypt($password) {
    if (!empty($password)) {
        $salt = strlen($password) > 2 ? substr($password, 0, 2) : 'f3x93J3';
        $str = hash_hmac('sha256', $password, $salt);
        return $str;
    } else {
        return false;
    }
}

/**
 * 创建token
 * 算法： MD5(用户参数,true) + MD5(用户密码) + base64encode(用户参数)
 * 长度：         16        +  32           +   变长
 * 
 * @param type $password 用户密码
 * @param type $param   用户参数
 * @return boolean  
 */
function create_token($password, $param = array()) {
    if (!empty($password)) {
        $param = token_param($param);
        $param = token_build_txt($param);
        if (!empty($param)) {
            return strtoupper(sf_md5_16($param)) . strtoupper(md5($password)) . urlsafe_b64encode($param);
        } else {
            return false;
        }
    } else {
        return false;
    }
}

/**
 * 解密Token，返回用户信息
 * 逻辑：
 *   数据库查询1次
 * @param type $str
 * @return boolean
 */
function parse_token($str) {
    if (!empty($str)) {
        if (strlen($str) > 48) {
            $param_txt = substr($str, 0, 16);
            $password = strtolower(substr($str, 16, 32));
            $param = substr($str, 48);
            if ($user = safe_param_check($param_txt, $param, $password)) {
                return $user;
            }
        } else {
            return false;
        }
    } else {
        return false;
    }
}

/**
 * Token 第一部分 与 第三部分合法行校验 + 用户有效校验
 * @param type $param_txt
 * @param type $param
 * @param type $password
 * @return boolean
 */
function safe_param_check($param_txt, $param, $password) {
    if (empty($param_txt) || empty($param) || empty($password)) {
        return false;
    } else {
        $param = urldecode(urlsafe_b64decode($param));
        if ($param_txt == strtoupper(sf_md5_16($param))) {
            $param = explode('&', $param);
            $token_param = C('token_param');
            if (empty($token_param)) {
                $token_param = array(
                    'uid' => 0,
                    'un' => ''
                );
            }
            if (count($param) == count($token_param)) {
                $param = array_combine(array_keys($token_param), $param);
                $user = M('users')->find($param['uid']);
                if (empty($user)) {
                    return false;
                } else {
                    if ($password == md5($user['password'])) {
                        unset($user['password']);
                        return $user;
                    } else {
                        return false;
                    }
                }
            } else {
                return false;
            }
        } else {
            return false;
        }
    }
}

/**
 * 格式化token动态参数、
 * 格式：uid&realname,例如：145&大个子
 * @param type $param
 * @return boolean
 */
function token_build_txt($param) {
    if (!empty($param)) {
        $str = implode('&', array_values($param));
        return $str;
    } else {
        return false;
    }
}

/**
 * 返回token第三部分的【有序】参数
 * @param type $param
 * @return type
 */
function token_param($param) {
    $token_param = C('token_param');
    if (empty($token_param)) {
        $token_param = array(
            'uid' => 0,
            'un' => ''
        );
    }
    foreach ($token_param as $key => $val) {
        if (array_key_exists($key, $param)) {
            $param_t[$key] = empty($param[$key]) ? $val : $param[$key];
        }
    }
    if (empty($param_t)) {
        $param_t = $token_param;
    }
    return $param_t;
}

/**
 * 无乱码 MD5(,true) 16位加密 
 * @param type $str
 * @return type
 */
function sf_md5_16($str) {
    if (!empty($str)) {
        return substr(md5($str), 8, -8);
    } else {
        return '';
    }
}

/**
 * URL安全的 base64 加密
 * @param type $string
 * @return type
 */
function urlsafe_b64encode($string) {
    $data = base64_encode($string);
    $data = str_replace(array('+', '/', '='), array('-', '_', ''), $data);
    return $data;
}

/**
 * URL安全的 base64 解密
 * @param type $string
 * @return type
 */
function urlsafe_b64decode($string) {
    $data = str_replace(array('-', '_'), array('+', '/'), $string);
    $mod4 = strlen($data) % 4;
    if ($mod4) {
        $data .= substr('====', $mod4);
    }
    return base64_decode($data);
}
